﻿#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib")
#include <Windows.h>
#include <WS2tcpip.h>

//设置连接的客户端数量的最大值
#define MAX_NUM 1024

SOCKET cSocket[MAX_NUM];

//和客户端通信的线程函数
void Communication(int idx);

int count;

int main()
{
	count = 0;
	//1.确定协议版本
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
	{
		printf("请求的协议版本不是2.2版本!\n");
		//9.清理协议信息
		WSACleanup();
		return -1;
	}

	//2.创建socket
	SOCKET sSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (SOCKET_ERROR == sSocket)
	{
		printf("创建socket失败:%d\n", GetLastError());
		return -2;
	}
	printf("创建socket成功\n");

	//3.确定服务器的协议地址簇
	SOCKADDR_IN addr = { 0 };
	addr.sin_family = AF_INET;//和socket函数第一个参数保持一致
	//addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//本地ip地址
	inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.S_un.S_addr);//vs2013版本以上使用新的函数转换IP地址
	addr.sin_port = htons(10087);//大小端转换

	//4.绑定
	int r = bind(sSocket, (sockaddr*)&addr, sizeof addr);
	if (-1 == r)
	{
		printf("绑定失败:%d\n", GetLastError());

		//8. 断开连接
		closesocket(sSocket);

		//9. 清理协议版本信息
		WSACleanup();

	}
	printf("绑定成功\n");

	//5. 监听
	r = listen(sSocket, 10);
	if (-1 == r)
	{
		printf("监听失败:%d\n", GetLastError());

		//8. 断开连接
		closesocket(sSocket);

		//9. 清理协议版本信息
		WSACleanup();
		return -2;
	}
	printf("监听成功\n");

	//6. 等待客户端连接,要实现连接多个客户端就用循环反复调用accept函数
	for (int i = 0; i < MAX_NUM; i++)
	{
		cSocket[i] = accept(sSocket, NULL, NULL);//服务器在接受客户端连接的时候
		if (SOCKET_ERROR == cSocket[i])
		{
			printf("服务器崩溃:%d\n", GetLastError());

			//8. 断开连接
			closesocket(sSocket);
			//9. 清理协议版本信息
			WSACleanup();
			return -3;
		}
		printf("有客户端连接上服务器了!第%d个客户端连接\n",i);
		count++;

		//用多线程脱离连接循环，同理还可以使用I/O复用、多并发等方式
		//创建一个线程
		CreateThread(NULL, NULL,
			(LPTHREAD_START_ROUTINE)Communication,
			(LPVOID)i,
			NULL, NULL);

	}
	
	while (1);//停顿
	return 0;
}

void Communication(int idx)
{
	//7. 通信
	char buff[256] = { 0 };
	int r;
	char temp[256];
	while (1)
	{
		//接收信息
		r = recv(cSocket[idx], buff, 255, NULL);//从客户端接收信息
		//判断是否接收到信息
		if (r > 0)
		{
			buff[r] = 0;//添加结束符号
			printf("第%d个客户端发言:%s\n",idx, buff);//输出

			//发送给当前连接上服务器的所有客户端
			memset(temp, 0, 256);
			sprintf(temp, "%d:%s", idx, buff);
			for (int i = 0; i < count; i++)
			{
				send(cSocket[i], temp, strlen(temp), NULL);
			}
		}
	}
}